package cn.sgy.infrastructure.designpattern.strategy;

import cn.sgy.infrastructure.base.initevent.ApplicationInitializingEvent;
import cn.sgy.infrastructure.base.util.ApplicationContextHolder;
import cn.sgy.infrastructure.convention.error.code.SystemErrorInfo;
import cn.sgy.infrastructure.convention.error.exception.ServiceException;
import cn.sgy.infrastructure.convention.error.exception.SystemException;
import cn.sgy.infrastructure.convention.error.util.QuickThrow;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;

import java.util.HashMap;
import java.util.Map;

/**
 * @author sgy
 * @description 策略选择器
 * @date 2023-02-28
 */
@Slf4j
public class AbstractStrategyChoose implements ApplicationListener<ApplicationInitializingEvent> {
    public AbstractStrategyChoose() {
    }

    /**
     * 保存所有策略执行器
     * key->mark生成的标识
     * value->策略执行器（里面规定了这个策略执行什么样的业务，相当于策略本身）
     */
    private final Map<String, AbstractExecuteStrategy> abstractExecuteStrategyMap = new HashMap<>();


    /**
     * 根据mark查询具体策略
     *
     * @param mark 策略标识
     * @return 实际执行策略
     */
    public AbstractExecuteStrategy choose(String mark) {
        return abstractExecuteStrategyMap.get(mark);
    }

    /**
     * 根据mark查询具体策略并执行
     *
     * @param mark         策略标识
     * @param requestParam 执行策略入参
     * @param <REQUEST>    执行策略入参范型
     */
    public <REQUEST> void chooseAndExecute(String mark, REQUEST requestParam) {
        AbstractExecuteStrategy executeStrategy = choose(mark);
        if (executeStrategy != null) {
            executeStrategy.execute(requestParam);
        } else {
            log.error("[系统内部错误]策略未找到，mark=[{}]，requestParam=[{}]", mark, requestParam);
            QuickThrow.throwException(new SystemException(SystemErrorInfo.STRATEGY_NOT_FOUND_ERROR));
        }
    }

    /**
     * 根据mark查询具体策略并执行，并返回结果
     *
     * @param mark         策略标识
     * @param requestParam 参数
     * @param <REQUEST>    泛型
     * @param <RESPONSE>   泛型
     * @return 对应策略的执行结果
     */
    public <REQUEST, RESPONSE> RESPONSE chooseAndExecuteResp(String mark, REQUEST requestParam) {
        AbstractExecuteStrategy executeStrategy = choose(mark);
        if (executeStrategy != null) {
            return (RESPONSE) executeStrategy.executeResp(requestParam);
        } else {
            log.error("[系统内部错误]策略未找到，mark=[{}]，requestParam=[{}]", mark, requestParam);
            QuickThrow.throwException(new SystemException(SystemErrorInfo.STRATEGY_NOT_FOUND_ERROR));
        }
        return null;
    }

    @Override
    public void onApplicationEvent(ApplicationInitializingEvent applicationInitializingEvent) {
        Map<String, AbstractExecuteStrategy> actual = ApplicationContextHolder.getBeansOfType(AbstractExecuteStrategy.class);
        actual.forEach((k, v) -> {
            String mark = v.mark();
            AbstractExecuteStrategy strategy = abstractExecuteStrategyMap.get(mark);
            if (strategy != null) {
                log.error("[系统内部错误]策略初始化失败，当前mark对应的策略已存在，mark=[{}]", mark);
                QuickThrow.throwException(new ServiceException(SystemErrorInfo.STRATEGY_NOT_FOUND_ERROR));
            }
            abstractExecuteStrategyMap.put(mark,v);
        });
    }
}
